import copy
import logging
from common.timeutil import get_interval_end_pair
from common.mg_core.mg import get_report_template, get_report, insert_or_update
from .const import GAME_DCT
from common.es_core.report_creator import ReportCreator
from common.const import INTERVAL_TYPE_MAPPER
from common.es_core.es_interface import es_search_interface
from event_rule.dwc.integrated_report_rule.channel_analysis import CHANNEL_ANALYSIS_CONFIG

_LOGGER = logging.getLogger(__name__)


def _calc_ring_ratio_stats(resp_items, key_mapper):
    report_insufficient = False
    if len(resp_items) == 0:
        return dict()
    elif len(resp_items) < 2:
        report_insufficient = True
    ring_ratio = dict()
    for mapper in key_mapper:
        if mapper['key'] == 'day':
            ring_ratio['day'] = '环比'
            continue
        ring_ratio[mapper['key']] = 0
        if not report_insufficient:
            ring_ratio[mapper['key']] = resp_items[-1][mapper['key']] - resp_items[-2][mapper['key']]
    return ring_ratio


def _calc_average_stats(resp_items, key_mapper):
    if len(resp_items) == 0:
        return dict()
    ring_ratio = dict()
    for mapper in key_mapper:
        if mapper['key'] == 'day':
            ring_ratio['day'] = '平均'
            continue
        ring_ratio[mapper['key']] = 0
        for item in resp_items:
            ring_ratio[mapper['key']] += item[mapper['key']] / float(len(resp_items))
    return ring_ratio


def calc_ring_ratio_and_average_stats(resp_items, key_mapper):
    _resp_items = copy.deepcopy(resp_items)
    ring_ratio = _calc_ring_ratio_stats(_resp_items, key_mapper)
    resp_items = resp_items + [ring_ratio] if ring_ratio else resp_items
    average_stats = _calc_average_stats(_resp_items, key_mapper)
    resp_items = resp_items + [average_stats] if average_stats else resp_items
    return resp_items


def get_bet_analysis_report(start_time, end_time, interval_type, report_type, index):
    assert report_type in ('bet_amount', 'bet_amount_avg', 'bet_user', 'tax_amount',
                           'profit_amount', 'profit_margin',)
    condition = dict(updated_at={'$gte': start_time, '$lte': end_time}, interval_type=interval_type)
    bet_reports, _ = get_report(index, 'integrated_bet_analysis_report', condition,
                                '-updated_at', disable_paginate=True)
    game_dct = GAME_DCT.get(index, {})
    resp_items, resp_item_dct = list(), dict()
    for bet_report in bet_reports:
        game_key = bet_report.get('bet_order_sub_type')
        report_date = bet_report.get('day')
        resp_item_dct.setdefault(report_date, {})
        resp_item_dct[report_date].setdefault(game_key, 0)
        value = bet_report.get(report_type, 0)
        if report_type in ('bet_amount', 'bet_amount_avg') and value == 0:
            value = bet_report.get('valid_' + report_type, 0)
        resp_item_dct[report_date][game_key] += value
    for report_date, report in resp_item_dct.items():
        report['day'] = report_date
        for game in game_dct:
            if game['key'] not in report:
                report[game['key']] = 0
        resp_items.append(report)
    resp_items = sorted(resp_items, key=lambda k: k['day'])
    return resp_items


def get_channel_analysis_report(merchant_name, target_time, interval_type, specific_chn):
    start_time, end_time = get_interval_end_pair(INTERVAL_TYPE_MAPPER[interval_type], target_time, 0, week_start=5,
                                                 calc_full_range=True)
    sort_by, size = '-register_user', 5
    condition = dict(updated_at={'$gte': start_time, '$lte': start_time}, interval_type=interval_type)
    if specific_chn:
        sort_by, size = 'updated_at', 7
        start_time, _ = get_interval_end_pair(INTERVAL_TYPE_MAPPER[interval_type], target_time, 7, week_start=5)
        condition['updated_at']['$gte'] = start_time
        condition['_chn'] = specific_chn
    channel_report, total_count = get_report(merchant_name, 'integrated_channel_report', condition,
                                             sort_by, size=size, disable_paginate=False)
    if not specific_chn:
        resp_item, chn_list = [], []
        for idx, report in enumerate(channel_report):
            report['rank'] = idx + 1
            chn_list.append(report['_chn'])
            resp_item.append(report)
        condition['_chn'] = {"$nin": chn_list}
        dynamic_argument_dct = _get_integrated_channel_report_dynamic_argument_dct(start_time, end_time, merchant_name)
        others_channel_report, total_count = get_report(merchant_name, 'integrated_channel_report', condition,
                                                        sort_by, size=size, disable_paginate=False,
                                                        merge_report=True,
                                                        event_rule=CHANNEL_ANALYSIS_CONFIG,
                                                        time_interval_type=interval_type,
                                                        dynamic_argument_dct=dynamic_argument_dct)
        if others_channel_report:
            others = others_channel_report[0]
            others['_chn'], others['rank'] = '其他', '其他'
            channel_report = resp_item
            channel_report.append(others)
    return channel_report, total_count


def _get_integrated_channel_report_dynamic_argument_dct(start_time, end_time, index):
    aggregation_dsl = {
        "query": {
            "bool": {
                "filter": [
                    {"term": {"_event_id": "register"}},
                    {"range": {"_event_time": {"gte": start_time.timestamp(), "lt": end_time.timestamp()}}}
                ]
            }
        },
        "size": 0,
        "aggs": {
            "register_user": {
                "cardinality": {"field": "_user_id"},
            }
        }
    }
    resp_json = es_search_interface(index, aggregation_dsl)
    return dict(total_register_user=resp_json['aggregations']['register_user']['value'])


def integrated_channel_report_handler(interval_type, base_time, last_window, event_name, event_rule, index):
    """
    :param interval_type: 报表时间单位
    :param base_time: 报表时间
    :param last_window: 时间段偏移值
    :param event_name: 报表名
    :param event_rule: 报表配置
    :param index: 商户索引名
    :return: None
    """
    custom_not_filter = {"term": {"bet_order_user_type": 1}}
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window, week_start=5)
    dynamic_argument_dct = _get_integrated_channel_report_dynamic_argument_dct(start_time, end_time, index)
    user_pool = None
    collection = '_'.join(['integrated', event_name, 'report'])
    recharge_reports = ReportCreator.create_report(user_pool=user_pool, start_time=start_time, end_time=end_time,
                                                   event_rule=event_rule, index=index,
                                                   custom_not_filter=custom_not_filter,
                                                   dynamic_argument_dct=dynamic_argument_dct, to_group=True)
    for report in recharge_reports['list']:
        report_id = '-'.join([report[event_rule.get('group_by').replace('.keyword', '')],
                              str(start_time).split(' ')[0], interval_type.value])
        report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
        report_template.update(report)
        insert_or_update(report_template, database=index, collection=collection)


def integrated_report_handler(interval_type, base_time, last_window, event_name, event_rule, index):
    """
    :param interval_type: 报表时间单位
    :param base_time: 报表时间
    :param last_window: 时间段偏移值
    :param event_name: 报表名
    :param event_rule: 报表配置
    :param index: 商户索引名
    :return: None
    """
    custom_not_filter = {"term": {"bet_order_user_type": 1}}
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window, week_start=5)
    user_pool = None
    collection = '_'.join(['integrated', event_name, 'report'])
    report_template = get_report_template(start_time, interval_type)
    report_template.update(ReportCreator.create_report(user_pool=user_pool, start_time=start_time, end_time=end_time,
                                                       event_rule=event_rule, index=index,
                                                       custom_not_filter=custom_not_filter))
    insert_or_update(report_template, database=index, collection=collection)


def integrated_group_by_report_handler(interval_type, base_time, last_window, event_name, event_rule, index,
                                       disable_global_aggregate=None):
    """
    :param interval_type: 报表时间单位
    :param base_time: 报表时间
    :param last_window: 时间段偏移值
    :param event_name: 报表名
    :param event_rule: 报表配置
    :param index: 商户索引名
    :param disable_global_aggregate: 是否关闭全局聚合
    :return: None
    """
    custom_not_filter = {"term": {"bet_order_user_type": 1}}
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window, week_start=5)
    user_pool = None
    collection = '_'.join(['integrated', event_name, 'report'])
    if not disable_global_aggregate:
        report_template = get_report_template(start_time, interval_type)
        report_template.update(
            ReportCreator.create_report(user_pool=user_pool, start_time=start_time, end_time=end_time,
                                        event_rule=event_rule, index=index, custom_not_filter=custom_not_filter))
        report_template.update({event_rule.get('group_by').replace('.keyword', ''): 'all'})
        insert_or_update(report_template, database=index, collection=collection)
    recharge_reports = ReportCreator.create_report(user_pool=user_pool, start_time=start_time, end_time=end_time,
                                                   event_rule=event_rule, index=index,
                                                   custom_not_filter=custom_not_filter, to_group=True)
    for report in recharge_reports['list']:
        report_id = '-'.join([report[event_rule.get('group_by').replace('.keyword', '')],
                              str(start_time).split(' ')[0], interval_type.value])
        report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
        report_template.update(report)
        insert_or_update(report_template, database=index, collection=collection)
